﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Lightray.Hattrick.ChppLib;

namespace Lightray.Hattrick
{
    public class StorageHandler
    {
        private FileSystemStorage<ITrickStorageEntry> _storage;

        public StorageHandler(string id, string path)
        {
            _storage = new FileSystemStorage<ITrickStorageEntry>(path, new Guid(id));
        }

        public void ReadPairOfLatestEntries(out ITrickStorageEntry newestEntry, out ITrickStorageEntry referenceEntry)
        {
            newestEntry = referenceEntry = new ITrickStorageEntry();
            readPairOfEntries(ref newestEntry, ref referenceEntry);
        }

        public IList<ITrickStorageEntry> ReadAllEntries()
        {
            return readAllEntries();
        }

        public void WriteNewEntry(FetchResultEventArgs e)
        {
            _storage.Write(dateToEntryName(e.HattrickTime), buildEntry(e));
        }

        private void readPairOfEntries(ref ITrickStorageEntry newestEntry, ref ITrickStorageEntry referenceEntry)
        {
            var entryDates = from entryName in _storage.ListEntries()
                             orderby entryName descending
                             select dateFromEntryName(entryName);

            if (entryDates.Count() == 0)
                return;

            newestEntry = readEntry(entryDates.First());
            if (entryDates.Count() > 1)
                referenceEntry = readEntry(weekOldEntryOrClosest(entryDates));
        }

        private IList<ITrickStorageEntry> readAllEntries()
        {
            IList<ITrickStorageEntry> ret = new List<ITrickStorageEntry>();
            foreach (var entry in _storage.ListEntries())
            {
                ITrickStorageEntry e;
                try
                {
                    _storage.ReadEntry(entry, out e);
                }
                catch
                {                    
                    continue;
                }

                ret.Add(e);
            }

            return ret;
        }

        private DateTime weekOldEntryOrClosest(IEnumerable<DateTime> entryDates)
        {
            DateTime newestEntryDate = entryDates.First();

            var olderEntryDates = entryDates.Skip(1);
            foreach (var entryDate in olderEntryDates)
            {
                if ((newestEntryDate - entryDate).Days >= 7)
                    return entryDate;
            }

            return olderEntryDates.First();
        }

        private ITrickStorageEntry readEntry(DateTime entryName)
        {
            ITrickStorageEntry entry;
            _storage.ReadEntry(dateToEntryName(entryName), out entry);

            return entry;
        }
 
        private static string dateToEntryName(DateTime dt)
        {
            return dt.ToString("yyyyMMdd");
        }

        private static DateTime dateFromEntryName(string entryName)
        {
            return DateTime.ParseExact(entryName, "yyyyMMdd", null);
        }

        private ITrickStorageEntry buildEntry(FetchResultEventArgs e)
        {
            ITrickStorageEntry entry = new ITrickStorageEntry()
            {
                OffsetFromHattrickTime = e.OffsetFromHattrickTime,
                WrittenDate = e.HattrickTime,
                MyPlayers = e.Xmls.FirstOrDefault(getPlayersXml),
                MyYouthPlayers = e.Xmls.FirstOrDefault(getYouthPlayersXml),
            };
            return entry;
        }

        private bool getPlayersXml(XDocument doc)
        {
            return doc.Root.Element("FileName").Value.ToLower() == "players.xml";
        }

        private bool getYouthPlayersXml(XDocument doc)
        {
            return doc.Root.Element("FileName").Value.ToLower() == "youthplayerlist.xml";
        }
    }
}
